/**
 * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springblade.modules.filesys.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import jdk.nashorn.internal.runtime.logging.Logger;
import lombok.AllArgsConstructor;
import lombok.extern.java.Log;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.filesys.entity.Cooperation;
import org.springblade.modules.filesys.entity.FileNode;
import org.springblade.modules.filesys.service.ICooperationService;
import org.springblade.modules.filesys.vo.CooperationVO;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * 控制器
 *
 * @author Blade
 * @since 2022-01-02
 */
@RestController
@AllArgsConstructor
@RequestMapping("blade-filesys/fileops")
@Api(value = "", tags = "文件共享系统-文件操作接口")
@Slf4j
public class FileGeneralOPTController extends BladeController {
	private static String rootPath = System.getProperty("user.dir");
	private static String sourcePath = rootPath + File.separator + "files";
	// 线程间隔离对象，生成id用
	private static ThreadLocal<Integer> id = new ThreadLocal<Integer>();
	private ICooperationService cooperationService;

	/**
	 * 详情
	 */
	@GetMapping("/treeData")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "获取文件树数据 id生成策略为  层数+000+id")
	public R<List<FileNode>> treeData() {
		String userPath = this.getUserPath();
		if (!userPath.contains("resources")){
			FileUtil.mkdir(Paths.get(userPath,"resources").toString());
		}else {
			FileUtil.mkdir(userPath);
		}
		id.set(1);
		List<FileNode> fileTree = this.getFileTree(userPath, 1);
		return R.data(fileTree);
	}
	@GetMapping("/value")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "获取单文件内容")
	@ApiLog("获取单文件内容")
	public R<String> value(@RequestParam @ApiParam(required = true) String filePath) {
		String fileValue = FileUtil.readUtf8String(filePath);
		return R.data(fileValue);
	}
	@PostMapping("/upload")
	@ApiOperationSupport(order = 11)
	@ApiOperation(value = "上传文件")
	@ApiLog("上传文件")
	public R<String> upload(@RequestParam @ApiParam(required = true) String uploadPath,
							@RequestParam @ApiParam(required = true) MultipartFile file) {
		// 做校验只能上传sourcePath文件夹内
		if (StringUtil.isEmpty(uploadPath) || !uploadPath.contains(sourcePath)) {
			uploadPath = this.getUserPath();
		}
		FileUtil.mkdir(uploadPath);
		try {
			file.transferTo(Paths.get(uploadPath, file.getOriginalFilename()));
		} catch (IOException e) {
			e.printStackTrace();
			return R.fail("上传失败" + e.getMessage());
		}
		return R.success("上传成功");
	}
	@PostMapping("/download")
	@ApiOperationSupport(order = 13)
	@ApiOperation(value = "下载文件")
	@ApiLog("下载文件")
	public void download(@RequestParam @ApiParam(required = true) String filePath, HttpServletResponse response) throws UnsupportedEncodingException {
		File file = new File(filePath);
		String myFileName= URLEncoder.encode(file.getName(), "utf-8");
		response.setCharacterEncoding("UTF-8"); //设置编码字符
		response.setContentType("application/octet-stream;charset=UTF-8"); //设置下载内容类型
		response.setHeader("Content-disposition", "attachment;filename=" + myFileName);//设置下载的文件名称
		try (OutputStream out = response.getOutputStream() //创建页面返回方式为输出流，会自动弹出下载框
		) {
			FileUtil.writeToStream(file, out);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@PostMapping("/download/zip")
	@ApiOperationSupport(order = 14)
	@ApiOperation(value = "下载为Zip文件")
	@ApiLog("下载为Zip文件")
	public void downloadZip(@RequestParam @ApiParam(required = true) String filePath, HttpServletResponse response) {
		File zip = null;
		try (OutputStream out = response.getOutputStream() //创建页面返回方式为输出流，会自动弹出下载框
		) {
			zip = ZipUtil.zip(filePath);
			response.setCharacterEncoding("UTF-8"); //设置编码字符
			response.setContentType("application/octet-stream;charset=UTF-8"); //设置下载内容类型
			response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(zip.getName(), "utf-8"));//设置下载的文件名称
			FileUtil.writeToStream(zip, out);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			zip.delete();
		}
	}
	@PostMapping("/save")
	@ApiOperationSupport(order = 15)
	@ApiOperation(value = "保存文件内容")
	@ApiLog("保存文件内容")
	public R<String> save(@RequestParam @ApiParam(required = true) String filePath,
						  @RequestParam @ApiParam(required = true) String value) {
		try {
			FileUtil.writeUtf8String(value, filePath);
		} catch (Exception e) {
			log.error(e.getCause().toString());
			e.printStackTrace();
			return R.fail("保存失败" + e.getMessage());
		}
		return R.success("保存成功");
	}

	@PostMapping("/del")
	@ApiOperationSupport(order = 16)
	@ApiOperation(value = "文件删除(包括文件夹)")
	@ApiLog("文件删除(包括文件夹)")
	public R<String> del(@RequestParam @ApiParam(required = true) String filePath) {
		try {
			boolean del = FileUtil.del(filePath);
			if (del == false) {
				return R.fail("删除失败");
			}
		} catch (Exception e) {
			log.error(e.getCause().toString());
			e.printStackTrace();
			return R.fail("删除失败" + e.getMessage());
		}
		return R.success("删除成功");
	}

	@PostMapping("/modify/name")
	@ApiOperationSupport(order = 17)
	@ApiOperation(value = "修改文件名(包括文件夹)")
	@ApiLog("修改文件名(包括文件夹)")
	public R<String> modifyName(@RequestParam @ApiParam(required = true) String filePath,
								@RequestParam @ApiParam(required = true) String name) {
		try {
			// isRetainExt为true时，保留扩展名
			FileUtil.rename(new File(filePath), name, true, true);
		} catch (Exception e) {
			log.error(e.getCause().toString());
			e.printStackTrace();
			return R.fail("修改失败" + e.getMessage());
		}
		return R.success("修改成功");
	}

	@PostMapping("/mkdir")
	@ApiOperationSupport(order = 18)
	@ApiOperation(value = "新建文件夹")
	@ApiLog("新建文件夹")
	public R<String> mkdir(@RequestParam @ApiParam(required = true) String filePath,
						   @RequestParam @ApiParam(required = true) String name) {
		try {
			FileUtil.mkdir(String.valueOf(Paths.get(filePath, name)));
		} catch (Exception e) {
			log.error(e.getCause().toString());
			e.printStackTrace();
			return R.fail("新建文件夹失败" + e.getMessage());
		}
		return R.success("新建文件夹成功");
	}

	@PostMapping("/mkfile")
	@ApiOperationSupport(order = 18)
	@ApiOperation(value = "新建文件")
	@ApiLog("新建文件")
	public R<String> mkfile(@RequestParam @ApiParam(required = true) String filePath,
							@RequestParam @ApiParam(required = true) String name) {
		try {
			File file = FileUtil.newFile(String.valueOf(Paths.get(filePath, name)));
			boolean newFile = file.createNewFile();
			if (newFile == false) {
				return R.fail("新建文件失败");
			}
		} catch (Exception e) {
			log.error(e.getCause().toString());
			e.printStackTrace();
			return R.fail("新建文件失败" + e.getMessage());
		}
		return R.success("新建文件成功");
	}
	/**
	 * 递归获取无限层级文件树
	 * id生成策略为  层数+000+id
	 *
	 * @param filePath
	 * @param level
	 * @return
	 */
	private List<FileNode> getFileTree(String filePath, int level) {
		List<FileNode> list = new ArrayList<>();
		for (File file : FileUtil.ls(filePath)) {
			FileNode fileNode = new FileNode();
			int tempId = Integer.valueOf(level + "000" + id.get());
			fileNode.setId(tempId);
			fileNode.setLevel(level);
			fileNode.setName(file.getName());
			fileNode.setPath(file.getPath());
			fileNode.setType(file.isDirectory() ? 0 : 1);
			id.set(id.get() + 1);
			if (file.isDirectory()) {
				fileNode.setChild(this.getFileTree(file.getPath(), level + 1));
			} else {
				fileNode.setChild(null);
			}
			list.add(fileNode);
		}
		return list;
	}
	private String getUserPath() {
		try {
			// User user = AuthUtil.getUser();
			//String userName = user.getUserName();
			return Paths.get(sourcePath,org.springblade.core.secure.utils.SecureUtil.getUser().getAccount()).toString();
		} catch (Exception e) {
			return sourcePath;
		}
	}

}
